package com.itany.shop.controller;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 石小俊
 * @date 2023年10月31日 11:14
 */
@WebServlet("*.file")
public class FileServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = request.getServletPath();
        switch (path) {
            case "/upload.file":
                upload(request, response);
                break;
            case "/download.file":
                download(request, response);
                break;
            case "/download2.file":
                download2(request, response);
                break;
            default:
                PrintWriter out = response.getWriter();
                out.println("<h1 style='color:red;'>您访问的资源不存在,请检查请求是否正确</h1>");
        }
    }

    protected void upload(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 下面的方法只适用于获取普通表单数据,不支持二进制流
//        String username = request.getParameter("username");
//        String file = request.getParameter("file");
//        System.out.println("username:"+username+",file:"+file);

        // 获取请求中的二进制流数据,必须通过请求获取到对应的流
//        InputStream in = request.getInputStream();
//        byte[] b = new byte[1024];
//        int i = in.read(b);
//        System.out.println(new String(b,0,i));
        // 到这一步为止,已经可以读取到请求中的所有数据
        // 此时需要解析请求中的信息,通过IO实现文件上传
        // 但是由于请求中数据较为繁琐,解析过程比较麻烦
        // 因此,可以使用第三方工具帮我们进行解析
        // 目前主流工具是apache提供的commons-fileupload
        // 该工具依赖于commons-io
        // 导入对应的两个依赖

        // 使用第三方工具对请求数据进行解析

        // 1.获取解析工厂
        DiskFileItemFactory factory = new DiskFileItemFactory();

        // 2.使用该工厂生产对应的解析器
        ServletFileUpload upload = new ServletFileUpload(factory);

        try {
            // 3.解析请求
            List<FileItem> fileItems = upload.parseRequest(request);
            Map<String,FileItem> items = new HashMap<>();
            for(FileItem fileItem : fileItems){
//                if("file".equals(fileItem.getFieldName())){
//                    System.out.println("文件名:"+fileItem.getName());
//                    // 使用默认编码读取文件内容
//                    System.out.println("文件内容:"+fileItem.getString());
//                    // 使用指定编码读取文件内容
//                    System.out.println("文件内容:"+fileItem.getString("utf-8"));
//                    // 上传
//                }else if("username".equals(fileItem.getFieldName())){
//                    System.out.println("用户名:"+fileItem.getString());
//                }
                // 将name属性值作为Map集合的key,将存储的对象作为Map集合的值
                items.put(fileItem.getFieldName(),fileItem);
            }

            System.out.println("用户名:"+items.get("username").getString());
            System.out.println("文件名:"+items.get("file").getName());
            System.out.println("文件内容:"+items.get("file").getString());

            // 获取存放文件的服务器地址
//            String path = getServletContext().getRealPath("/upload");
            // 取出需要上传到服务器的文件
            FileItem file = items.get("file");
            // 将该文件上传到服务器的指定地址
            // 参数为目标文件
//            file.write(new File(path,file.getName()));

            // 拓展1.某些文件不允许上传,例如:jsp
            String fileName = file.getName();
            if(fileName.endsWith(".jsp")){
                request.setAttribute("uploadMsg","上传失败,不允许上传jsp文件");
                request.getRequestDispatcher("/jsp/upload.jsp").forward(request,response);
                return;
            }

            // 拓展2.在服务器中初始是没有目标的
            // 要求:在服务器根目录创建一个upload目录用于上传文件
            // 且在upload目录中存在无数个子目录,每天创建一个子目录,以年月日命名
            // 当前上传的文件上传到对应子目录中
            String path = getServletContext().getRealPath("/upload/"+new SimpleDateFormat("yyyyMMdd").format(new Date()));
            File f = new File(path);
            f.mkdirs();

            // 拓展3.为了防止存在重名的文件,要求为每一个上传的文件进行重命名
            // 在原有文件的基础上添加一个毫秒值的后缀
            fileName = fileName.substring(0,fileName.lastIndexOf("."))+"-"+new Date().getTime()+fileName.substring(fileName.lastIndexOf("."));

            file.write(new File(path,fileName));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void download(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 指定需要下载的资源所在的地址
        String path = getServletContext().getRealPath("/lib/jstl-1.2.jar");

        FileInputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(path);
            out = response.getOutputStream();

//            byte[] b = new byte[10240];
//            int i;
//            while((i = in.read(b)) != -1){
//                out.write(b,0,i);
//            }

            // 此时可以实现下载,但是可能存在浏览器不识别的资源也使用了在线打开的方式
            // 此时打开的文件全部都是乱码
            // 对于某些文件我们需要以附件的方式进行下载
            // 该方式遵循MIME协议
            // 在Servlet中通过响应头信息进行体现
            // 在响应头中存在一个属性content-disposition
            // 该属性的值有两种
            // 1.attachment:表示以附件的方式下载
            // 2.inline:在线打开
//            response.setHeader("content-disposition","attachment");
            // 此时以附件方式下载的时候,其文件名默认使用的是当前的请求名
            // 在content-disposition属性中可以指定文件名
            // 其值的格式 attachment;filename=xxx
//            response.setHeader("content-disposition","attachment;filename=jstl-1.2.jar");
            // 如果文件名是一个中文,必须转换成ISO-8859-1的编码
            response.setHeader("content-disposition",new String("attachment;filename=中文".getBytes(),"ISO-8859-1"));

            byte[] b = new byte[10240];
            int i;
            while((i = in.read(b)) != -1){
                out.write(b,0,i);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    protected void download2(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = getServletContext().getRealPath("/js/jquery-3.4.1.min.js");

        FileInputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(path);
            out = response.getOutputStream();

            response.setHeader("content-disposition","inline");

            byte[] b = new byte[10240];
            int i;
            while((i = in.read(b)) != -1){
                out.write(b,0,i);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

}
